/*
 * Item.java
 *
 * Created on 16 February 2005, 19:33
 */

package org.datamining.guha.rule;

import org.datamining.guha.model.literal.Literal;

/**
 * This class is to represent particular property in the original data.
 * It ia used both as antecedent and succedent.
 *
 * @author Lukas Vlcek
 */
public class Item {
    
    public static int CANNOT_BE_USED = -3;
    
    public static int CANNOT_BE_SHIFTED = -2;
    public static int NOT_SHIFTED = -1;
    public static int SHIFT_SUCCESS = 0;
    
    private String name;
    private String[] intervalNames;
    private Literal[] intervalLiterals;
    // Which Literal is currently used (should be only one at a time!).
    private boolean[] usedLiterals;
    // Which Literals are disabled (should be not used due to low support).
    private boolean[] disabledLiterals;
    
    /** Creates a new instance of Item
     *
     * @param name can be any String. Its purpose is to provide user facility
     *             to describe this item in words (give it some name).
     * @param intervalNames String[] array with descriptions of individual
     *                      dichotomized intervals (e.g: "10 <= x < 30").
     * @param intervalLiterals Literal[] array. Its length must be the same
     *                         as interalNames array.
     */
    public Item(String name, String[] intervalNames, Literal[] intervalLiterals)
    throws IllegalArgumentException {
        if (name != null && name.trim().length() > 0) {
            if (intervalNames.length > 0 &&
                    intervalNames.length == intervalLiterals.length) {
                this.name = name;
                this.intervalNames = intervalNames;
                this.intervalLiterals = intervalLiterals;
                
                int len = intervalNames.length;
                usedLiterals = new boolean[len];
                disabledLiterals = new boolean[len];
                for (int i = 0; i < len; i++) {
                    usedLiterals[i] = false;
                    disabledLiterals[i] = false;
                }

            } else {
                throw new IllegalArgumentException("intervalNames.length must be equal to intervalLiterals.length");
            }
        } else {
            throw new IllegalArgumentException("name is no set properly");
        }
        
    }

    /**
     * Constructor with specified name and initial size of internal arrays.
     */
    public Item(String name, int size) {
        
        int len = size*2;
        
        this.name = name;
        intervalLiterals = new Literal[len];
        intervalNames = new String[len];
        
        usedLiterals = new boolean[len];
        disabledLiterals = new boolean[len];
        for (int i = 0; i < len; i++) {
            usedLiterals[i] = false;
            disabledLiterals[i] = false;
        }
    }
    
    public String getName() {
        return name;
    }

    public String[] getIntervalNames() {
        return intervalNames;
    }

    public void setIntervalNames(String[] names) {
    	intervalNames = names;
    }
    
    public Literal[] getIntervalLiterals() {
        return intervalLiterals;
    }
    
    public Literal getInteravlLiteral(int index) {
        return intervalLiterals[index];
    }
    
    /**
     * @return true is any of its allowed Literals is used.
     * That means if any of usedLiterals[x] is set to true and
     * disabledLiterals[x] == false
     */
    public boolean isUsed() {
        for (int i = 0; i < usedLiterals.length; i++) {
            if (usedLiterals[i] == true && disabledLiterals[i] == false) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Try to shift used Literal to right.
     * @return int Which can be one of CANTBESHIFTED, SHIFTSUCCESS, NOTSHIFTED
     */
    public int shiftUsed() {
        int len = usedLiterals.length;
        
        // It is empty.
        if (len < 1) { return Item.CANNOT_BE_SHIFTED; }
        
        // If last Literal is used then there is nothing to shift.
        if (usedLiterals[len-1] == true) {
            return Item.CANNOT_BE_SHIFTED;
        }
        int freePosition = -1;
        // Find left-most free position from right.
        for (int i = len-1; i >= 0; i--) {
            if (usedLiterals[i] == false && disabledLiterals[i] == false) {
                freePosition = i;
            }
            if (usedLiterals[i] == true) {
                if (freePosition != -1) {
                    usedLiterals[i] = false;
                    usedLiterals[freePosition] = true;
                    return Item.SHIFT_SUCCESS;
                } else {
                    return Item.CANNOT_BE_SHIFTED;
                }
            }
        }
        return Item.NOT_SHIFTED;
    }
    
    /**
     * We assume that no Literal is used. UsedLiterals[x] == false for all x.
     * Use first free Literal from left.
     *
     * @return position of first used Literal or CANTBEUSED.
     */
    public int useFirstPossibleLiteral() {
        for (int i = 0; i < usedLiterals.length; i++) {
            if (usedLiterals[i] == false && disabledLiterals[i] == false) {
                usedLiterals[i] = true;
                return i;
            }
        }
        return Item.CANNOT_BE_USED;
    }
    
    /**
     * Set all usedLiterals[x] to false
     */
    public void resetUsed() {
        for (int i = 0; i < usedLiterals.length; i++) {
            usedLiterals[i] = false;
        }
    }
    
    /**
     * Set all disabledLiterals[x] to false
     */
    public void resetDisabled() {
        for (int i = 0; i < disabledLiterals.length; i++) {
            disabledLiterals[i] = false;
        }
    }

    public boolean[] getUsedLiterals() {
        return usedLiterals;
    }

    public boolean[] getDisabledLiterals() {
        return disabledLiterals;
    }
    
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append(name + "\n");

        for (int i = 0; i < intervalLiterals.length; i++) {
            sb.append(i + " = " + intervalNames[i] + " : " +
                      intervalLiterals[i] + " : " +
                      usedLiterals[i] + " : " +
                      disabledLiterals[i] + "\n");
        }
        return sb.toString();
    }
}
